package com.huwei.util;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.springframework.data.redis.connection.DataType;
import org.springframework.data.redis.connection.RedisZSetCommands.Limit;
import org.springframework.data.redis.connection.RedisZSetCommands.Range;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.data.redis.core.ZSetOperations.TypedTuple;
import org.springframework.data.redis.core.query.SortQuery;

/**
 * redis工具
 * @author huwei
 *
 */
public class RedisUtil {

	private RedisTemplate<String, Object> redisTemplate;
	
	public RedisUtil(RedisTemplate<String, Object> redisTemplate) {
		this.redisTemplate = redisTemplate;
	}
	
	//========================= comm =================================//
	
	public <T> T execute(RedisCallback<T> action) {
		return redisTemplate.execute(action);
	}
	
	public <T> T execute(RedisCallback<T> action ,boolean exposeConnection) {
		return redisTemplate.execute(action, exposeConnection);
	}
	
	public <T> T execute(RedisCallback<T> action ,boolean exposeConnection ,boolean pipeline) {
		return redisTemplate.execute(action, exposeConnection, pipeline);
	}
	
	public <T> T execute(SessionCallback<T> session) {
		return redisTemplate.execute(session);
	}
	
	public List<Object> executePipeline(SessionCallback<?> session) {
		return redisTemplate.executePipelined(session);
	}
	
	public List<Object> executePipeline(RedisCallback<?> action){
		return redisTemplate.executePipelined(action);
	}
	
	public RedisTemplate<String, Object> getRedisTemplate(){
		return this.redisTemplate;
	}
	
	//========================= key   =================================//
	
	public Set<String> keys(String pattern) {
		return redisTemplate.keys(pattern);
	}
	
	public boolean isKey(String key) {
		Set<String> keys = keys(key);
		return Objects.nonNull(keys) && !keys.isEmpty();
	}
	
	
	public boolean delKey(String ...keys) {
		if(Objects.nonNull(keys) && keys.length == 1) {
			redisTemplate.delete(keys[0]);
		}
		else {
			try {
				redisTemplate.delete(Arrays.asList(keys));
			} catch (Exception e) {
				return false;
			}
		}
		
		return true;
	}
	
	/**
	 * 设置过期时间，时间单位秒
	 * @param key
	 * @param time
	 */
	public boolean expireOnSeconds(String key ,long timeout) {
		return redisTemplate.expire(key, timeout, TimeUnit.SECONDS);
	}
	
	public boolean expireOnMilliseconds(String key ,long timeout) {
		return redisTemplate.expire(key, timeout, TimeUnit.MILLISECONDS);
	}
	
	public boolean expire(String key ,long timeout ,TimeUnit unit) {
		return redisTemplate.expire(key, timeout, unit);
	}
	
	public Long getExpire(String key) {
		return redisTemplate.getExpire(key);
	}
	
	public boolean persist(String key) {
		return redisTemplate.persist(key);
	}
	
	public boolean move(String key ,int dbIndex) {
		return redisTemplate.move(key, dbIndex);
	}
	
	public boolean rename(String oldKey ,String newKey) {
		try {
			redisTemplate.rename(oldKey, newKey);
		} catch (Exception e) {
			return false;
		}
		return true;
	}
	
	public boolean renameIfAbsent(String oldKey ,String newKey) {
		try {
			redisTemplate.renameIfAbsent(oldKey, newKey);
		} catch (Exception e) {
			return false;
		}
		return true;
	}
	
	public DataType type(String key) {
		return redisTemplate.type(key);
	}
	
	public String randomKey() {
		return redisTemplate.randomKey();
	}
	
	public byte[] dump(String key) {
		return redisTemplate.dump(key);
	}
	
	/**
	 * 从redis仓库中恢复数据
	 * @param key 新设置的键值，该键值不能重复
	 * @param val redis仓库中存储的数据的序列化值，redis会对该值进行校验，不正确将不被恢复
	 * @param timeToLive 新创建的key的过期时间，0表示不定过期时间 ；在redis中默认该时间单位为毫秒
	 * @param unit
	 * @return
	 */
	public boolean restore(String key ,byte[] val ,long timeToLive ,TimeUnit unit) {
		boolean restored = false;
		try {
			redisTemplate.restore(key, val, timeToLive, unit);
			restored = isKey(key);
		} catch (Exception e) {
		}
		return restored;
	}
	
	//========================= 事务   =================================//

	/**
	 * 开启事务：
	 * 说明：
	 * 	redis中所有单条命令都是原子操作的；
	 *  事务的作用只是将开启事务后的所有redis命令添加到可执行的队列中，redis负责的工作相当于是批量执行这些命令，而不被打断；
	 *  但是，在事务执行过程中，所有的命令都将被执行，不管前后的命令是否成功或者失败；
	 */
	public void multi() {
		redisTemplate.multi();
	}
	
	/**
	 * 执行事务
	 * @return 事务中所有命令的返回结果；
	 */
	public List<Object> exec(){
		return redisTemplate.exec();
	}
	
	/**
	 * 取消事务，以及删除对key的监视
	 */
	public void discard() {
		redisTemplate.discard();
	}
	
	/**
	 * 监听给定的key，在事务执行时，给定的key被改变，都将导致对该key的任何操作失败；
	 * @param keys
	 */
	public void watch(String ...keys) {
		if(Objects.nonNull(keys) && keys.length == 1) {
			redisTemplate.watch(keys[0]);
		}
		else {
			redisTemplate.watch(Arrays.asList(keys));
		}
	}
	
	/**
	 * 取消对所有key的监听
	 * 注意：
	 * 	当时事务执行完毕，即使用了exec方法之后，对所有的key的监听任务就已经完成了，所以就不需要再使用unwatch方法了；
	 *  当使用了discard方法后，也会取消对所有key的监听，所有也不需要再使用unwatch方法了
	 */
	public void unwatch() {
		redisTemplate.unwatch();
	}
	
	public OpsForString opsForString() {
		return new OpsForString();
	}
	
	public ValueOperations<String, Object> opsForStringOfRedisTemplate(){
		return redisTemplate.opsForValue();
	}
	
	//========================= 排序  =================================//
	
	/**
	 * 对给定的key所表示的list 、hash、set 、zset类型的对象进行排序
	 * @param sortQuery 排序规则，具体可查阅redis的sort命令
	 * @return
	 */
	public List<Object> sort(SortQuery<String> sortQuery){
		return redisTemplate.sort(sortQuery);
	}
	
	/**
	 * list数据操作对象；
	 * @return
	 */
	public OpsForList opsForList() {
		return new OpsForList();
	}
	/**
	 * 从redistemplate中获取list数据类型的操作对象；
	 * @return
	 */
	public ListOperations<String ,Object> opsForListOfRedisTemplate() {
		return redisTemplate.opsForList();
	}
	
	public OpsForHash opsForHash() {
		return new OpsForHash();
	}
	
	public HashOperations<String, Object, Object> opsForHashOfRedisTemplate(){
		return redisTemplate.opsForHash();
	}
	
	public OpsForSortedSet opsForSortedSet() {
		return new OpsForSortedSet();
	}
	
	public ZSetOperations<String, Object> opsZSetOperationsOfRedisTemplate(){
		return redisTemplate.opsForZSet();
	}
	
	/**
	 * redis string type ops 
	 * @title redis learn test
	 * @author huwei
	 *
	 */
	public class OpsForString {
		public Object get(String key) {
			return redisTemplate.opsForValue().get(key);
		}
		
		public Object getAndSet(String key ,Object value) {
			return redisTemplate.opsForValue().getAndSet(key, value);
		}
		
		/**
		 * 获取给定的key值，并截取指定的长度
		 * @param key
		 * @param start 字符串的起始下标，从0开始，也可以是负数，表示从尾部开始向头部查找，-1表示最后一个
		 * @param end 字符串的结束下标，截取时将包含该下标的值；
		 * @return
		 */
		public String getSubstring(String key ,long start ,long end) {
			return redisTemplate.opsForValue().get(key, start, end);
		}
		
		public Long strLen(String key) {
			return redisTemplate.opsForValue().size(key);
		}
		
		public boolean getBit(String key ,long offset) {
			return redisTemplate.opsForValue().getBit(key, offset);
		}
		
		public boolean setBit(String key ,long offset ,boolean value) {
			return redisTemplate.opsForValue().setBit(key, offset, value);
		}
		
		public void set(String key ,Object value) {
			redisTemplate.opsForValue().set(key, value);
		}
		
		public void set(String key ,Object value ,long timeout ,TimeUnit unit) {
			redisTemplate.opsForValue().set(key, value, timeout, unit);
		}
		
		public void setIfAbsent(String key ,Object value) {
			redisTemplate.opsForValue().setIfAbsent(key, value);
		}
		
		/**
		 * 将给定下标位置的值替换成新值，如果给定的下标超过给定key当前值的有效长度，则在空余的下标中填充0
		 * @param key
		 * @param value
		 * @param offset
		 */
		public void setInOffset(String key ,Object value ,long offset) {
			redisTemplate.opsForValue().set(key, value, offset);
		}
		
		/**
		 * 向给定的key的值的尾部追加数据 ，注意：返回的值是当前数据的整体长度
		 * @param key
		 * @param value
		 * @return
		 */
		public Integer append(String key ,String value) {
			return redisTemplate.opsForValue().append(key, value);
		}
		
		public Long incrBy(String key ,long value) {
			return redisTemplate.opsForValue().increment(key, value);
		}
		
		public Double incrBy(String key ,Double value) {
			return redisTemplate.opsForValue().increment(key, value);
		}
		
		public List<Object> multiGet(String ...keys){
			if(Objects.isNull(keys)) {
				throw new IllegalArgumentException("keys cannot is null");
			}
			return redisTemplate.opsForValue().multiGet(Arrays.asList(keys));
		}
		
		public void multiSet(Map<String ,Object> map) {
			 redisTemplate.opsForValue().multiSet(map);
		}
		/**
		 * 当且仅当map中给定的key都不存在时，数据才会被存储；
		 * @param map
		 */
		public void multiSetIfAbsent(Map<String ,Object> map) {
			redisTemplate.opsForValue().multiSetIfAbsent(map);
		}
	}

	/**
	 * redis list 数据类型的操作对象；
	 * @tile redis test
	 * @author huwei
	 */
	public class OpsForList {
		/**
		 * 获取给定下标位置的值
		 * @param key
		 * @param index
		 * @return
		 */
		public Object lindex(String key ,long index) {
			return redisTemplate.opsForList().index(key, index);
		}
		
		/**
		 * 从列表的头部弹出一个数据（获取并删除头部的第一个数据）
		 * @param key
		 * @return
		 */
		public Object lpop(String key) {
			return redisTemplate.opsForList().leftPop(key);
		}
		
		/**
		 * 从列表的尾部弹出一个数据
		 * @param key
		 * @return
		 */
		public Object rpop(String key) {
			return redisTemplate.opsForList().rightPop(key);
		}
		
		/**
		 * 从sourceKey列表的尾部弹出一个数据并添加到给定的另一目标列表中
		 * @param sourceKey
		 * @param destinationKey
		 * @return
		 */
		public Object rpopLpush(String sourceKey ,String destinationKey) {
			return redisTemplate.opsForList().rightPopAndLeftPush(sourceKey, destinationKey);
		}
		
		/**
		 * 使用阻塞的方式从sourceKey列表的尾部弹出一个数据，并将个数据添加到另一个目标列表中；
		 * @param sourceKey
		 * @param destinationKey
		 * @param timeout
		 * @param unit
		 * @return
		 */
		public Object bRpopLpush(String sourceKey ,String destinationKey ,long timeout ,TimeUnit unit) {
			return redisTemplate.opsForList().rightPopAndLeftPush(sourceKey, destinationKey, timeout, unit);
		}
		
		/**
		 * 给定一个timeout的时间，并以阻塞的方式从目标列表中的尾部获取一个数据，如果该列表尾部有数据，则直接返回，如果没有数据，则等待给定的timeout时间
		 * @param key
		 * @param timeout
		 * @param unit
		 * @return
		 */
		public Object bRpop(String key ,long timeout ,TimeUnit unit) {
			return redisTemplate.opsForList().rightPop(key, timeout, unit);
		}
		
		/**
		 * 给定一个timeout的时间，并以阻塞的方式从目标列表中的头部获取一个数据，如果该列表头部有数据，则直接返回，如果没有数据，则等待给定的timeout时间
		 * @param key
		 * @param timeout
		 * @param unit
		 * @return
		 */
		public Object bLpop(String key ,long timeout ,TimeUnit unit) {
			return redisTemplate.opsForList().leftPop(key, timeout, unit);
		}
		
		/**
		 * 从列表中获取给定返回的数据
		 * @param key
		 * @param start 列表的起始位置，从0开始，也可以是负数，负数表示从列表的尾部开始计数，-1表示最后一个列表值；
		 * @param end 列表的结束位置，将包含该位置；
		 * @return
		 */
		public List<Object> lrange(String key ,long start ,long end){
			return redisTemplate.opsForList().range(key, start, end);
		}
		/**
		 * 向给定的列表中插入数据，并返回当前列表整体长度
		 * @param key
		 * @param value
		 * @return
		 */
		public Long lpush(String key ,Object value) {
			return redisTemplate.opsForList().leftPush(key, value);
		}
		
		public Long lpushAll(String key ,Object ...values) {
			return redisTemplate.opsForList().leftPushAll(key, values);
		}
		
		/**
		 * 当且仅当给定的目标列表以及存在的时候才添加数据；
		 * @param key
		 * @param value
		 * @return
		 */
		public Long lpushIfPresent(String key ,Object value) {
			return redisTemplate.opsForList().leftPushIfPresent(key, value);
		}
		
		public Long rpush(String key ,Object value) {
			return redisTemplate.opsForList().rightPush(key, value);
		}
		
		public Long rpushAll(String key ,Object ...values) {
			return redisTemplate.opsForList().rightPushAll(key, values);
		}
		
		public Long rpushIfPresent(String key ,Object value) {
			return redisTemplate.opsForList().rightPushIfPresent(key, value);
		}
		
		/**
		 * 改变给定下标位置的值
		 * @param key
		 * @param value
		 * @param index
		 */
		public void lset(String key ,Object value ,long index) {
			redisTemplate.opsForList().set(key, index, value);
		}
		
		/**
		 * 将列表截取为指定返回的长度
		 * @param key
		 * @param start
		 * @param end
		 */
		public void ltrim(String key ,long start ,long end){
			redisTemplate.opsForList().trim(key, start, end);
		}
		
		public Long llen(String key) {
			return redisTemplate.opsForList().size(key);
		}
		
		/**
		 * 将列表中给定的多个的value值删除count个；
		 * @param key
		 * @param count 删除相同value的数量，0 或者 比当前value个数多都表示删除全部的value值；
		 * @param value
		 * @return
		 */
		public Long lrem(String key ,int count ,Object value) {
			return redisTemplate.opsForList().remove(key, count, value);
		}
	}
	
	/**
	 * redis hash type ops
	 * @title redis learn test
	 * @author huwei ${date}
	 *
	 */
	public class OpsForHash {
		
		private HashOperations<String, Object, Object> ops;
		
		private OpsForHash() {
			this.ops = redisTemplate.opsForHash();
		}
		/**
		 * 从给定的key所表示的map中获取给定hashKey的值；
		 * @param key
		 * @param hashKey
		 * @return
		 */
		public Object hget(String key ,Object hashKey) {
			return ops.get(key, hashKey);
		}
		
		public List<Object> hmget(String key ,Object ...hashKeys){
			if(Objects.isNull(hashKeys)) {
				throw new IllegalArgumentException("hashkey cannot is null");
			}
			return ops.multiGet(key, Arrays.asList(hashKeys));
		}
		
		public List<Object> hvals(String key){
			return ops.values(key);
		}
		
		public Map<Object ,Object> hgetAll(String key){
			return ops.entries(key);
		}
		
		public Cursor<Map.Entry<Object, Object>> hscan(String key ,ScanOptions scanOptions){
			return ops.scan(key, scanOptions);
		}
		
		public void hset(String key ,Object hashKey ,Object value) {
			ops.put(key, hashKey, value);
		}
		
		public void hsetIfAbsent(String key ,Object hashKey ,Object value) {
			ops.putIfAbsent(key, hashKey, value);
		}
		
		public void hmset(String key ,Map<Object ,Object> map) {
			ops.putAll(key, map);
		}
		
		public Long hdel(String key ,Object ...hashKeys) {
			return ops.delete(key, hashKeys);
		}
		
		public Long hlen(String key) {
			return ops.size(key);
		}
		
		public Set<Object> hkeys(String key ,String pattern) {
			return ops.keys(pattern);
		}
		
		public boolean hexists(String key ,Object hashKey) {
			return ops.hasKey(key, hashKey);
		}
	}


	/**
	 * redis set type ops
	 * @titile redis learn test
	 * @author huewi
	 *
	 */
	public class OpsForSet{
		private SetOperations<String, Object> set;
		
		private OpsForSet() {
			this.set = redisTemplate.opsForSet();
		}
		
		public Object spop(String key) {
			return set.pop(key);
		}
		
		public Set<Object> smembers(String key){
			return set.members(key);
		}
		
		public Cursor<Object> sscan(String key ,ScanOptions scanOptions) {
			return set.scan(key, scanOptions);
		}
		
		public Object sRandMember(String key) {
			return set.randomMember(key);
		}
		
		public Long sadd(String key ,Objects ...values) {
			return set.add(key, values);
		}
		
		public boolean sIsMember(String key ,Object member) {
			return set.isMember(key, member);
		}
		
		public Long srem(String key ,Object ...values) {
			return set.remove(key, values);
		}
		
		public void smove(String sourceKey ,String destinationKey ,Object value) {
			set.move(sourceKey, value, destinationKey);
		}
		
		public Long scard(String key) {
			return set.size(key);
		}
		
		/**
		 * 获取多个set集合的差集
		 * @param key
		 * @param otherKeys
		 * @return
		 */
		public Set<Object> sdiff(String key ,String ...otherKeys){
			assertNotNull(otherKeys);
			return set.difference(key, Arrays.asList(otherKeys));
		}
		
		/**
		 * 获取多个set集合的差集，并将结果保存到指定的set集合中；
		 * @param destinationKey
		 * @param key
		 * @param otherKeys
		 * @return
		 */
		public Long sdiffStore(String destinationKey ,String key ,String ...otherKeys) {
			assertNotNull(otherKeys);
			return set.differenceAndStore(key, Arrays.asList(otherKeys), destinationKey);
		}
		
		/**
		 * 获取多个set集合的交集
		 * @param key
		 * @param otherKeys
		 * @return
		 */
		public Set<Object> sinter(String key ,String ...otherKeys){
			assertNotNull(otherKeys);
			return set.intersect(key, Arrays.asList(otherKeys));
		}
		
		/**
		 * 获取多个set集合的交集，并将结果保存到给定的set集合中
		 * @param destinationKey
		 * @param key
		 * @param otherKeys
		 * @return
		 */
		public Long sinterStore(String destinationKey ,String key ,String ...otherKeys) {
			assertNotNull(otherKeys);
			return set.intersectAndStore(key, Arrays.asList(otherKeys), destinationKey);
		}
		
		/**
		 * 获取多个set集合的并集
		 * @param key
		 * @param otherKeys
		 * @return
		 */
		public Set<Object> sunion(String key ,String ...otherKeys){
			assertNotNull(otherKeys);
			return set.union(key, Arrays.asList(otherKeys));
		}
		/**
		 * 获取多个set集合的并集，并将结果保存到给定的set集合中
		 * @param destinationKey
		 * @param key
		 * @param otherKeys
		 * @return
		 */
		public Long sunionStore(String destinationKey ,String key ,String ...otherKeys) {
			assertNotNull(otherKeys);
			return set.unionAndStore(key, Arrays.asList(otherKeys), destinationKey);
		}
	}
	
	/**
	 * redis sorted set type ops
	 * @title redis learn test
	 * @author huwei
	 *
	 */
	public class OpsForSortedSet {
		
		private ZSetOperations<String, Object> sortedSet;
		
		private OpsForSortedSet() {
			this.sortedSet = redisTemplate.opsForZSet();
		}
		
		public boolean zadd(String key ,Object value ,Double score) {
			return sortedSet.add(key, value, score);
		}
		
		public Long zadd(String key ,Set<TypedTuple<Object>> tuples) {
			return sortedSet.add(key, tuples);
		}
		
		/**
		 * 从zset中获取给定范围的值
		 * @param key
		 * @param start
		 * @param end
		 * @return
		 */
		public Set<Object> zRange(String key ,long start ,long end){
			return sortedSet.range(key, start, end);
		}
		
		/**
		 * 从zset中获取给定范围的值 ，并倒叙排列
		 * @param key
		 * @param start
		 * @param end
		 * @return
		 */
		public Set<Object> zRevRange(String key ,long start ,long end){
			return sortedSet.reverseRange(key, start, end);
		}
		
		/**
		 * 从zset中获取给定范围的值和值的分数，对应redis的命令为：zrange key start end [withscores]
		 * @param key
		 * @param start
		 * @param end
		 * @return
		 */
		public Set<TypedTuple<Object>> zRangeWithScores(String key ,long start ,long end) {
			return sortedSet.rangeWithScores(key, start, end);
		}
		
		/**
		 * 从zset中获取给定范围的值和值的分数，并且以倒叙的方式排列
		 * @param key
		 * @param start
		 * @param end
		 * @return
		 */
		public Set<TypedTuple<Object>> zRevRangeWithScores(String key, long start ,long end){
			return sortedSet.reverseRangeWithScores(key, start, end);
		}
		
		/**
		 * 从zset集合中获取在给定分数值之间的数据；
		 * @param key
		 * @param min
		 * @param max
		 * @return
		 */
		public Set<Object> zrangeByScore(String key ,double min ,double max){
			return sortedSet.rangeByScore(key, min, max);
		}
		
		/**
		 * 从zset集合中获取给定score分数之间的数据，并以倒叙的方式排列返回；
		 * @param key
		 * @param min
		 * @param max
		 * @return
		 */
		public Set<Object> zRevRangeByScore(String key ,double min ,double max){
			return sortedSet.reverseRangeByScore(key, min, max);
		}
		/**
		 * 从zset集合中获取给定score分数之间的数据和数据的分数；
		 * @param key
		 * @param min
		 * @param max
		 * @return
		 */
		public Set<TypedTuple<Object>> zrangeByScoreWithScores(String key ,double min ,double max){
			return sortedSet.rangeByScoreWithScores(key, min, max);
		}
		/**
		 * 从zset集合中获取给定score分数之间的数据和数据的分数，并以倒叙的方式排列返回
		 * @param key
		 * @param min
		 * @param max
		 * @return
		 */
		public Set<TypedTuple<Object>> zRevRangeByScoreWithScores(String key ,double min ,double max){
			return sortedSet.reverseRangeByScoreWithScores(key, min, max);
		}
		
		/**
		 * 通过字典表（2019-1-25时理解，字典表就是从字符a 到 z）获取给定字典范围中的数据；
		 * 注意：
		 * 注意：
		 * 注意：
		 * 	redis命令格式如下：
		 * 	zrangebylex key min max [limit offset count]
		 * 	示例：
		 * 	zrangebylex zset1 [a (z 
		 * 	示例含义：表示从字典a开始（[ 符号表示包含后面给定的字符） 到z( ( 符号表示不包含后面的字符)之间的数据
		 * [ 符号表示包含后面给定的字符
		 * ( 符号表示不包含后面的字符
		 * @param key
		 * @param range
		 * @return
		 */
		public Set<Object> zrangeByLex(String key ,org.springframework.data.redis.connection.RedisZSetCommands.Range range){
			return sortedSet.rangeByLex(key, range);
		}
		
		/**
		 * 通过字典表（2019-1-25时理解，字典表就是从字符a 到 z）获取给定字典范围中的数据；
		 * 注意：
		 * 注意：
		 * 注意：
		 * 	redis命令格式如下：
		 * 	zrangebylex key min max [LIMIT offset count]
		 * 	示例：
		 * 	zrangebylex zset1 [a (z limit 0 10
		 * 	示例含义：表示从字典a开始（[ 符号表示包含后面给定的字符） 到z( ( 符号表示不包含后面的字符)之间的数据
		 * [ 符号表示包含后面给定的字符
		 * ( 符号表示不包含后面的字符
		 * @param key
		 * @param range
		 * @return
		 */
		public Set<Object> zrangeByLex(String key ,Range range ,int offset ,int count){
			Limit limit = new Limit();
			limit.count(count);
			limit.offset(offset);
			return sortedSet.rangeByLex(key, range ,limit);
		}
		
		/**
		 * 将sourceKey0和sourceKey1的交集存储到新的目标集合中destinationKey
		 * @param destinationKey
		 * @param sourceKey0
		 * @param sourceKey1
		 * @return
		 */
		public Long zInterStore(String destinationKey ,String sourceKey0 ,String sourceKey1) {
			return sortedSet.intersectAndStore(sourceKey0, sourceKey1, destinationKey);
		}
		
		public Long zInterStoreAndMore(String destinationKey ,String sourceKey0 ,String ...otherKeys) {
			if(otherKeys == null) {
				return zInterStore(destinationKey, sourceKey0, null);
			}
			else {
				return sortedSet.intersectAndStore(sourceKey0, Arrays.asList(otherKeys), destinationKey);
			}
		}
		
		/**
		 * 求给定集合的并集，并存储到指定的key
		 * @param destinationKey
		 * @param sourceKey0
		 * @param sourceKey1
		 * @return
		 */
		public Long zUnionStore(String destinationKey ,String sourceKey0 ,String sourceKey1) {
			return sortedSet.unionAndStore(sourceKey0, sourceKey1, destinationKey);
		}
		
		public Long zUnionStoreAndMore(String destinationKey ,String sourceKey0 ,String ...otherKeys) {
			if(otherKeys == null) {
				return zUnionStore(destinationKey, sourceKey0, null);
			}
			else {
				return sortedSet.unionAndStore(sourceKey0, Arrays.asList(otherKeys), destinationKey);
			}
		}
		
		/**
		 * 以游标的形式扫描给定的集合
		 * @param key
		 * @param scanOptions
		 * @return
		 */
		public Cursor<TypedTuple<Object>> zscan(String key ,ScanOptions scanOptions) {
			return sortedSet.scan(key, scanOptions);
		}
		
		/**
		 * 返回在给定分数之间所有的元素的个数
		 * @param key
		 * @param minScore
		 * @param maxScore
		 * @return
		 */
		public Long zcount(String key ,double minScore ,double maxScore) {
			return sortedSet.count(key, minScore, maxScore);
		}
		
		/**
		 * 返回给定元素在有序集合中的索引位置
		 * @param key
		 * @param value
		 * @return
		 */
		public Long zRank(String key ,Object value) {
			return sortedSet.rank(key, value);
		}
		
		/**
		 * 返回给定元素在有序集合中的倒序的索引位置；
		 * @param key
		 * @param value
		 * @return
		 */
		public Long zRevRank(String key ,Object value) {
			return sortedSet.reverseRank(key, value);
		}

		/**
		 * 从有序集合中删除给定的元素
		 * @param key
		 * @param values
		 * @return
		 */
		public Long zrem(String key ,Object ...values) {
			
			return sortedSet.remove(key, values);
		}
		
		/**
		 * 从有序集合中删除给定索引下标范围内的元素
		 * @param key
		 * @param startIndex
		 * @param endIndex
		 * @return
		 */
		public Long zremRangeByRank(String key ,long startIndex ,long endIndex) {
			return sortedSet.removeRange(key, startIndex, endIndex);
		}
		
		/**
		 * 从有序集合中删除给定的分数范围内的元素；
		 * @param key
		 * @param minScore
		 * @param maxScore
		 * @return
		 */
		public Long zremRangeByScore(String key ,double minScore ,double maxScore) {
			return sortedSet.removeRangeByScore(key, minScore, maxScore);
		}
		
		/**
		 * 返回有序集合元素的数量
		 * @param key
		 * @return
		 */
		public Long zcard(String key) {
			return sortedSet.size(key);
		}
	}
	
	private void assertNotNull(Object obj) {
		if(Objects.isNull(obj)) {
			throw new IllegalArgumentException("obj  cannot is null");
		}
	}
	
}
